import os
import time

import requests

import win32gui
import win32api
import win32con
import win32clipboard

import pyperclip

from utils import dm,dd
from db import session, Log, ExceptionLog
from gui_config import config
from exceptions import *

def lock_wrapper(func):
    def wrapper(*argc,**kvarg):
        self = argc[0]
 
        if self.lock is not None:
            self.lock.acquire()
            #print("acquire")
        result = func(*argc,**kvarg)
        if self.lock is not None:
            #print("release")
            self.lock.release()
        return result
    wrapper.__name__ = func.__name__
    return wrapper

def create_time():
    """
    @return :返回当时时间，格式为：年-月-日 时:分:秒
    """
    import datetime
    return datetime.datetime.utcnow()

class worker(object):
    """
    先启动模拟器，再抓取模拟器句柄

    """
    def __init__(self, backend:"后台根地址", lock:"锁", config_entity, old_title = "BlueStacks App Player"):
        super(worker, self).__init__()
        self.backend = backend
        self.user_account = config_entity['user_account']
        self.IMSI = config_entity['IMSI']
        self.pay_password=config_entity['pay_password']
        self.login_password = config_entity['login_password']
        self.max = float(config_entity['max'])
        self.auto_stop = float(config_entity['auto_stop'])
        self.level = config_entity['level'].split(",")

        self.old_title = old_title
        self.base_picture_path= "image/"
        self.session = requests.Session()
        self.is_background = 0
        self.targethwnd = 0
        self.lock = lock
        self.risk = 50000
        self.getHwnd()

    @lock_wrapper
    def key_single(self,char):
        win32gui.SetForegroundWindow(self.hwnd)
        dm.KeyPressChar(char)

    @lock_wrapper  
    def key_word(self,word,delay=0.01):
        for char in word:
            self.key_single(char)
            time.sleep(delay)
    
    @lock_wrapper    
    def paste(self):
        win32gui.SetForegroundWindow(self.hwnd)
        time.sleep(0.1)
        dm.KeyDown(17)
        time.sleep(0.1)
        dm.KeyDown(86)
        time.sleep(0.1)
        dm.KeyUp(86)
        time.sleep(0.1)
        dm.KeyUp(17)
        time.sleep(0.1)

    @lock_wrapper  
    def copy(self,data):
        return dm.SetClipboard(data)
        return pyperclip.copy(data)

    @lock_wrapper
    def c_and_p(self,data):
        self.copy(data)
        time.sleep(1)
        self.paste()

    def run(self):
        try:
            self.goto_zz()
            time.sleep(1)
            response = self.get_a_ticket()
            while response.get("err") == 1:
               response = self.get_a_ticket()
            if response.get("err") != 0:
                raise GetTicketException(str(response))
            try:
                self.wid = response.get("wid")
                self.money = response.get("money","0")
                self.bank_name = response.get("bank_name")
                self.bank_account = response.get("bank_account")

                if float(self.money) > self.risk:
                    raise MoneyOutstripRisk(self.wid,"金额超过设置的风控了")

                total_money = self.total_money_pay_today()
                if float(self.money) + total_money > self.max:
                    raise MoneyOutstripBankLimt(self.wid,"金额超过设置的上限了")
                print("当前总金额:",total_money,"任务金额:",self.money)
                print("自动停止金额:",self.auto_stop,"任务金额:",self.money)
                log = self.create_log()
                self.fill_bank_info(self.bank_name,self.bank_account,self.money)
                time.sleep(3)
                if self.check_is_ticket_locked() and self.pay():
                #if self.pay():
                    self.commit_log(log)
                    self.commit_a_ticket()
                    if float(self.money) + total_money > self.auto_stop:
                        raise StopException("超过自动停止上限")
            except InPayException as e:
                self.log_exception(e)
                print(e)
                self.unlock_a_ticket("自动化："+str(e))
            except BeforePayException as e:
                self.log_exception(e)
                print(e)
                self.unlock_a_ticket("自动化："+str(e))
            except AfterPayException as e:
                self.log_exception(e)
                print(e)
                self.mark_a_ticket("警告！输入U盾密码后网络卡顿,无法确认出款情况")
                raise StopException("警告！输入U盾密码后网络卡顿,无法确认出款情况")
                #self.unlock_a_ticket("警告！自动化："+str(e))
            except BankInfoErrorException as e:
                self.log_exception(e)
                print(e)
                self.unlock_a_ticket("自动化："+str(e))
            except BeforeFillBankInfoErrorException as e:
                self.log_exception(e)
                print(e)
                self.unlock_a_ticket("自动化："+str(e))
            except Exception as e:
                raise LockedException(self.wid,str(e))
        except GetMonitorHwndException as e:
            #获取不了模拟器句柄.需要手动操作
            raise e
        except GetTicketException as e:
            #向服务器获取任务时发生异常.需要检查网络
            raise e
        except StartBankAppException as e:
            #启动手机银行时触发的异常，需要人工确认情况
            raise e
        except LoginException as e:
            #银行登录异常
            raise e
        except LockedException as e:
            self.log_exception(e)
            print(e)
            self.unlock_a_ticket("自动化："+str(e))
        except Exception as e:
            self.log_exception(e)
            raise e
        finally:
            self.back()

    def screen_to_image(self):
        "return 截图的绝对路径"
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        cc=time.gmtime() 
        bmpname=str(cc[0])+str(cc[1])+str(cc[2])+str(cc[3]+8)+str(cc[4])+str(cc[5])+'.bmp'
        saveBitMap.SaveBitmapFile(saveDC, bmpname) 
        file = os.path.abspath(bmpname)
        dm.Capture(x1,y1,x2,y2,file)
        return file

    def getHwnd(self):
        self.hwnd = win32gui.FindWindow(None,self.old_title)
        if self.hwnd == 0:
            raise GetMonitorHwndException("模拟器句柄获取失败，请检查模拟器是否打开")

    @lock_wrapper        
    def left_click(self,x,y,rx=5,ry=5,reset=True):
        "右下偏移5,5"
        from_mouse_location = win32api.GetCursorPos()
        to_mouse_location = (x+rx,y+ry)
        win32gui.SetForegroundWindow(self.hwnd)
        self.mouse_move(from_mouse_location,to_mouse_location,action=self.action,reset=reset)

    def action(self):
        dm.LeftClick()

    @lock_wrapper      
    def mouse_move(self,x_y_from,x_y_to,action=lambda :"",reset=True):
        x,y = x_y_to
        if self.is_background == 1:
            pass
        dm.MoveTo(*x_y_to)
        action()
        time.sleep(0.05)
        if reset:
            dm.MoveTo(*x_y_from)

    def mouse_smooth(self,x_y_from,x_y_to,cost_time=1,smooth_function=lambda x_y_from,x_y_to:""):
        pass

    @lock_wrapper
    def findPicture_relative(self,pic_name,sim=0.8,dir=0,delta_color="000000",delay=0.05):
        pic_path = self.base_picture_path + pic_name
        win32gui.SetForegroundWindow(self.hwnd)
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        time.sleep(delay)
        res = dm.FindPicE(x1,y1,x2,y2,pic_path,delta_color,sim,dir)
        flag,x,y = res.split("|")
        if int(flag) < 0 :
            print("not found ",pic_name)
            return False,int(x),int(y)
        else:
            print("found",pic_name,x,y)
            return True,int(x),int(y)

    @lock_wrapper       
    def findPicture_relative_onlybool(self,pic_name,sim=0.8):
        flag,x,y = self.findPicture_relative(pic_name,sim=sim)
        return flag

    @lock_wrapper
    def findPicture_relative_and_click(self,pic_name,rx=5,ry=5,sim=0.84):
        flag,x,y = self.findPicture_relative(pic_name,sim)
        if flag:
            self.left_click(x,y,rx,ry)
        return flag
    
    @lock_wrapper
    def findPicture_absolute(self,pic_path,sim=0.9,dir=0,delta_color="000000"):
        if self.is_background == 0 :
            win32gui.SetForegroundWindow(self.hwnd)
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        res = dm.FindPicE(x1,y1,x2,y2,pic_path,delta_color,sim,dir)
        flag,x,y = res.split("|")
        if int(flag) < 0 :
            return False,int(x),int(y)
        else:
            return True,int(x),int(y)

    def wait_unit_findpic_or_timeout(self,pic_name,timeout=10,promise_check_time=3,sim=0.8):   
        start = time.time()
        run_time = 0
        while not self.findPicture_relative_onlybool(pic_name,sim=sim):
            run_time +=1
            if run_time > promise_check_time and time.time() - start > timeout:
                return False
            time.sleep(1)
        return True

    def wait_unit_pic404_or_timeout(self,pic_name,timeout=10,promise_check_time=3,sim=0.9):
        start = time.time()
        run_time = 0
        while self.findPicture_relative_onlybool(pic_name,sim=sim):
            run_time +=1
            if run_time > promise_check_time and time.time() - start > timeout:
                return False
            time.sleep(1)
        return True

    @lock_wrapper
    def back(self):
        flag,x,y = self.findPicture_absolute("image/back.bmp")
        if flag:
            self.left_click(x,y)

    def get_a_ticket(self):
        return self.session.get(self.backend+"/getAndLockTicket",params={"user_account":self.user_account,"level[]":self.level}).json()

    def unlock_a_ticket(self,message=''):
        return self.session.get(self.backend+"/unlockTicket",params={"wid":self.wid,'message':message}) 

    def mark_a_ticket(self,message):
        return self.session.get(self.backend+"/markTicket",params={"wid":self.wid,'message':message}) 

    def commit_a_ticket(self):
        return self.session.get(self.backend+"/commit",params={"wid":self.wid})

    def check_is_ticket_locked(self):
        try:
            res = self.session.get(self.backend+"/checkIsLocked",params={"wid":self.wid})
            print(res.content)
            return res.json().get("data",False)
        except Exception as e:
            return False


    def unBindWindow(self):
        if self.hwnd != 0 :
            dm.SetWindowText(self.hwnd,self.old_title)
            return dm.UnBindWindow()

    """以下是数据库相关操作"""
    def total_money_pay_today(self):
        import datetime
        now = create_time()
        c = datetime.timedelta(hours=now.hour+8,minutes=now.minute,seconds=now.second)
        q = session.query(Log).filter(Log.user_account == self.user_account,Log.last_update_time > now -c ,Log.is_commit == 1).values("money")
        total_money = sum([float(i[0]) for i in q])
        return total_money

    def create_log(self):
        t = create_time()
        wid = self.wid
        name = self.bank_name
        account = self.bank_account
        money = self.money
        user_account = self.user_account
        log = Log(wid=wid,name=name,account=account,money=money,user_account=user_account,create_time=t,last_update_time=t,is_lock=1)
        session.add(log)
        session.commit()
        print("新建log")
        return log

    def commit_log(self,log):
        log.is_commit = 1
        log.last_update_time = create_time()
        session.commit()

    def log_exception(self,exception):
        log = ExceptionLog(exception_class=str(type(exception)),exception_message=str(exception))
        if isinstance(exception,LockedException):
            log.wid=exception.wid
        session.add(log)
        session.commit()